package com.baihan.angus.app.game.common.util.media;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.baihan.angus.app.game.basic.utils.AppUtil;
import com.baihan.angus.app.game.basic.utils.Tooast;
import com.baihan.angus.app.game.basic.utils.net.NetConstant;
import com.baihan.angus.app.game.basic.views.LoadingDialog;
import com.baihan.angus.app.game.basic.views.image_watcher.ZoomImageView;
import com.baihan.angus.app.game.common.R;
import com.baihan.angus.app.game.common.data_center.remote.api.DownloadServer;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.Target;
import com.trello.rxlifecycle2.components.support.RxFragment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

public class MediaFragment extends RxFragment implements OnSaveMediaFileListener {

    private final int WHAT_RESEEK_TO_MIDDLE = 1;
    private final int WHAT_HIDE_PAUSE_BUTTON = 2;
    private IMediaInfo mMediaInfo;
    private static final String ARG_PARAM1 = "param1";
    protected boolean isFirstVisible = true;
    private Handler handler;

    private SurfaceView videoView;
    private ZoomImageView zoomImageView;
    private ImageView gifImageView;
    private ImageView unknowFile;
    private FrameLayout flVideoView;
    private Button btnPlay;
    private SurfaceHolder mSurfaceHolder;
    private MyVideoPlayer myVideoPlayer;
    private LoadingDialog mLoadingDialog;

    public MediaFragment() {
        // Required empty public constructor
    }

    public static MediaFragment newInstance(IMediaInfo param1) {
        MediaFragment fragment = new MediaFragment();
        Bundle args = new Bundle();
        args.putSerializable(ARG_PARAM1, param1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mMediaInfo = (IMediaInfo) getArguments().getSerializable(ARG_PARAM1);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_media, container, false);
    }

    @SuppressLint("HandlerLeak")
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        flVideoView = view.findViewById(R.id.flVideoView);
        btnPlay = view.findViewById(R.id.btnPlay);
        videoView = view.findViewById(R.id.videoView);
        unknowFile = view.findViewById(R.id.unknowFile);
        zoomImageView = view.findViewById(R.id.zoomImageView);
        gifImageView = view.findViewById(R.id.gifImageView);

        switch (MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath())) {
            case MediaType.IMAGE:
                zoomImageView.setVisibility(View.VISIBLE);
                loadImage(zoomImageView);
                break;
            case MediaType.VIDEO:
                flVideoView.setVisibility(View.VISIBLE);
                initSurfaceview();
                break;
            case MediaType.GIF:
                gifImageView.setVisibility(View.VISIBLE);
                loadGif(gifImageView);
                break;
            case MediaType.UNKNOW:
                unknowFile.setVisibility(View.VISIBLE);
                break;
        }

        handler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case WHAT_RESEEK_TO_MIDDLE:
                        myVideoPlayer.setSeekto(myVideoPlayer.getDuration() / 2);
                        break;
                    case WHAT_HIDE_PAUSE_BUTTON:
                        if (myVideoPlayer.isPlaying()) {
                            btnPlay.setVisibility(View.INVISIBLE);
                        }
                        break;
                }
            }
        };
    }

    private void loadImage(ImageView imageView) {
        Glide.with(this).load(mMediaInfo.getMediaPath()).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC).into(imageView);
    }

    private void loadGif(ImageView gifImageView) {
        Glide.with(this).asGif().load(mMediaInfo.getMediaPath()).diskCacheStrategy(DiskCacheStrategy.RESOURCE).into(gifImageView);
    }

    protected void showLoading(String tag) {
        if (mLoadingDialog == null) {
            mLoadingDialog = new LoadingDialog(getActivity());
        }
        mLoadingDialog.showDialog(tag);
    }

    protected void hideLoading(String tag) {
        if (mLoadingDialog != null) {
            mLoadingDialog.hideDialog(tag);
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (mMediaInfo != null && MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
            if (!isVisibleToUser) {
                if (MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
                    if (myVideoPlayer.stopPlay()) {
                        btnPlay.setBackgroundResource(R.mipmap.basic_ic_start_play);
                        if (btnPlay.getVisibility() != View.VISIBLE)
                            btnPlay.setVisibility(View.VISIBLE);
                    }
                }
            }
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mMediaInfo != null && MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
            if (MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
                if (myVideoPlayer.isPlaying()) {
                    if (myVideoPlayer.stopPlay()) {
                        btnPlay.setBackgroundResource(R.mipmap.basic_ic_start_play);
                        if (btnPlay.getVisibility() != View.VISIBLE)
                            btnPlay.setVisibility(View.VISIBLE);
                    }

                }
            }
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mMediaInfo != null && MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
            if (MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath()) == MediaType.VIDEO) {
                handler.sendEmptyMessage(WHAT_RESEEK_TO_MIDDLE);
            }
        }
    }

    private void initSurfaceview() {
        btnPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (myVideoPlayer.isInitFinish()) {
                    if (myVideoPlayer.isPlaying()) {
                        if (myVideoPlayer.pausePlay())
                            btnPlay.setBackgroundResource(R.mipmap.basic_ic_start_play);
                    } else {
                        if (myVideoPlayer.isStop()) {
                            if (myVideoPlayer.replayPlay()) {
                                btnPlay.setBackgroundResource(R.mipmap.basic_ic_pause_play);
                                handler.sendEmptyMessageDelayed(WHAT_HIDE_PAUSE_BUTTON, 2000);
                            }
                        } else {
                            if (myVideoPlayer.playVideo()) {
                                btnPlay.setBackgroundResource(R.mipmap.basic_ic_pause_play);
                                handler.sendEmptyMessageDelayed(WHAT_HIDE_PAUSE_BUTTON, 2000);
                            }
                        }
                    }
                }
            }
        });
        videoView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myVideoPlayer.isPlaying() && btnPlay.getVisibility() != View.VISIBLE) {
                    btnPlay.setVisibility(View.VISIBLE);
                    handler.sendEmptyMessageDelayed(WHAT_HIDE_PAUSE_BUTTON, 2000);
                }
            }
        });
        myVideoPlayer = new MyVideoPlayer(mMediaInfo.getMediaPath()) {
            @Override
            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
                changeVideoSize(mp);
            }

            @Override
            public void onCompletion(MediaPlayer mp) {
                btnPlay.setVisibility(View.VISIBLE);
                btnPlay.setBackgroundResource(R.mipmap.basic_ic_start_play);
            }

            @Override
            public void onPrepared(MediaPlayer mp) {
                super.onPrepared(mp);
                handler.sendEmptyMessage(WHAT_RESEEK_TO_MIDDLE);
            }

            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                return false;
            }
        };
        mSurfaceHolder = videoView.getHolder();
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                myVideoPlayer.setDisplay(holder);//给mMediaPlayer添加预览的SurfaceHolder

            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }

    public void changeVideoSize(MediaPlayer mp) {
        int videoWidth = mp.getVideoWidth();
        int videoHeight = mp.getVideoHeight();

        //根据视频尺寸去计算->视频可以在sufaceView中放大的最大倍数。
        float max;
        int surfaceWidth = videoView.getWidth();
        int surfaceHeight = videoView.getHeight();
        if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
            //竖屏模式下按视频宽度计算放大倍数值
            max = Math.max((float) videoWidth / (float) surfaceWidth, (float) videoHeight / (float) surfaceHeight);
        } else {
            //横屏模式下按视频高度计算放大倍数值
            max = Math.max(((float) videoWidth / (float) surfaceHeight), (float) videoHeight / (float) surfaceWidth);
        }

        //视频宽高分别/最大倍数值 计算出放大后的视频尺寸
        videoWidth = (int) Math.ceil((float) videoWidth / max);
        videoHeight = (int) Math.ceil((float) videoHeight / max);

        //无法直接设置视频尺寸，将计算出的视频尺寸设置到surfaceView 让视频自动填充。
        videoView.setLayoutParams(new FrameLayout.LayoutParams(videoWidth, videoHeight));
    }

    @Override
    public void onDestroyView() {
        if (myVideoPlayer != null) {
            myVideoPlayer.release();
        }
        handler.removeCallbacksAndMessages(null);
        handler = null;
        super.onDestroyView();
    }

    @Override
    public void saveFile() {
        if (isSaving) return;
        switch (MediaTypeUtil.getMediaType(mMediaInfo.getMediaPath())) {
            case MediaType.IMAGE:
                saveMediaFile(System.currentTimeMillis() + ".jpg");
                break;
            case MediaType.VIDEO:
                String suffix = mMediaInfo.getMediaPath().substring(mMediaInfo.getMediaPath().lastIndexOf("."));
                if (mMediaInfo.getMediaPath().startsWith("http")) {
                    downloadMedia(mMediaInfo.getMediaPath(), System.currentTimeMillis() + suffix);
                } else {
                    saveMediaFile(System.currentTimeMillis() + suffix);
                }
                break;
            case MediaType.GIF:
                saveMediaFile(System.currentTimeMillis() + ".gif");
                break;
        }
    }

    private boolean isSaving = false;

    private void saveMediaFile(final String newName) {

        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {

                if (AppUtil.saveFileToApp(getActivity(), getImagePath(mMediaInfo.getMediaPath()), newName)) {
                    emitter.onNext(AppUtil.APP_FILE_SAVE_PATH + newName);
                } else {
                    emitter.onNext(null);
                }
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).compose(this.<String>bindToLifecycle())
                .subscribe(new Observer<String>() {

                    Disposable disposable;

                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                        isSaving = true;

                    }

                    @Override
                    public void onNext(String a) {
                        isSaving = false;
                        if (!TextUtils.isEmpty(a)) {
                            Tooast.success(getString(R.string.alreadySaveTo).replace("#P", a));
                        } else {
                            Tooast.warning(getString(R.string.savefailed));
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        isSaving = false;
                        Tooast.warning(getString(R.string.savefailed));
                        if (disposable != null && !disposable.isDisposed())
                            disposable.dispose();
                    }

                    @Override
                    public void onComplete() {
                        isSaving = false;
                        if (disposable != null && !disposable.isDisposed())
                            disposable.dispose();
                    }
                });
    }

    private void downloadMedia(String url, final String newName) {
        showLoading("downloadMedia");
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(NetConstant.BASE_HOST)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        retrofit.create(DownloadServer.class).download(url).subscribeOn(Schedulers.io())
                .observeOn(Schedulers.single())
                .map(new Function<ResponseBody, String>() {
                    @Override
                    public String apply(ResponseBody responseBody) throws Exception {
                        try {
                            long total = responseBody.contentLength();//需要下载的总大小
                            long current = 0;
                            InputStream inputStream = responseBody.byteStream();
                            FileOutputStream fileOutputStream = new FileOutputStream(AppUtil.APP_FILE_SAVE_PATH + newName);
                            byte[] bytes = new byte[1024];
                            int len = 0;
                            while ((len = inputStream.read(bytes)) != -1) {
                                fileOutputStream.write(bytes, 0, len);
                                fileOutputStream.flush();
                                current = current + len;
//                                Loog.d("MediaFragment", "已经下载=" + current + " 需要下载=" + total);
                            }
                            fileOutputStream.flush();
                            fileOutputStream.close();
                            inputStream.close();
                            //保存图片后发送广播通知更新数据库
                            Uri uri = Uri.fromFile(new File(AppUtil.APP_FILE_SAVE_PATH + newName));
                            getActivity().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
                            return AppUtil.APP_FILE_SAVE_PATH + newName;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return null;
                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .compose(this.<String>bindToLifecycle())
                .subscribe(new Observer<String>() {
                    Disposable disposable;

                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                        isSaving = true;
                        Tooast.normalInfo(getString(R.string.isSaving));
                    }

                    @Override
                    public void onNext(String b) {
                        hideLoading("downloadMedia");
                        isSaving = false;
                        if (!TextUtils.isEmpty(b)) {
                            Tooast.success(getString(R.string.alreadySaveTo).replace("#P", b));
                        } else {
                            Tooast.warning(getString(R.string.savefailed));
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        hideLoading("downloadMedia");
                        isSaving = false;
                        Tooast.warning(getString(R.string.savefailed));
                        if (disposable != null && !disposable.isDisposed())
                            disposable.dispose();
                    }

                    @Override
                    public void onComplete() {
                        hideLoading("downloadMedia");
                        isSaving = false;
                        if (disposable != null && !disposable.isDisposed())
                            disposable.dispose();
                    }
                });
    }

    /**
     * Glide 获得图片缓存路径
     */
    private String getImagePath(String imgUrl) {
        String path = null;
        FutureTarget<File> future = Glide.with(this)
                .load(imgUrl)
                .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
        try {
            File cacheFile = future.get();
            path = cacheFile.getAbsolutePath();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        return path;
    }

}